package com.golxen.utils;

import java.io.File;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class ScanUtils {

    // 通过扫描某个包下的所有类，确定要加载的类
    public static Set<Class<?>> scanClass(String packageName) throws IOException, ClassNotFoundException {

        Set<Class<?>> classes = new HashSet<Class<?>>();
        String packagePath = packageName.replace(".", "/");
        Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources(packagePath);
        while (resources.hasMoreElements()) {
            URL url = resources.nextElement();
            if (url.getProtocol().equals("file")) {
                String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                File file = new File(filePath);
                if (file.exists()) {
                    findInPath(classes, filePath, packageName);
                }
            } else if (url.getProtocol().equals("jar")) {
                JarFile jar;
                try {
                    jar = ((JarURLConnection) url.openConnection()).getJarFile();
                    Enumeration<JarEntry> entries = jar.entries();
                    while (entries.hasMoreElements()) {
                        JarEntry entry = entries.nextElement();
                        String name = entry.getName();
                        if (name.charAt(0) == '/') {
                            name = name.substring(1);
                        }
                        if (name.startsWith(packagePath)) {
                            int idx = name.lastIndexOf('/');
                            if (idx != -1) {
                                packageName = name.substring(0, idx).replace('/', '.');
                            }
                            if ((idx != -1)) {
                                if (name.endsWith(".class") && !entry.isDirectory()) {
                                    String className = name.substring(packageName.length() + 1, name.length() - 6);
                                    try {
                                        classes.add(Thread.currentThread().getContextClassLoader()
                                                .loadClass(packageName + '.' + className));
                                    } catch (ClassNotFoundException e) {
                                        e.printStackTrace();
                                    }
                                }
                            }
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return classes;
    }

    private static void findInPath(Set<Class<?>> classSet, String packagePath, String packageName)
            throws ClassNotFoundException {

        File f = new File(packagePath);
        if (f.isDirectory()) {
            File[] files = f.listFiles();
            for (File f1 : files) {
                String name = f1.getName();
                String packagePath1 = packagePath + "/" + name;
                String packageName1 = packageName + "." + name;
                if (f1.isDirectory()) {
                    findInPath(classSet, packagePath1, packageName1);
                } else if (name.endsWith(".class")) {
                    String className = packageName1.substring(0, packageName1.length() - 6);
                    classSet.add(Thread.currentThread().getContextClassLoader().loadClass(className));
                }
            }
        }
    }

}
